
#define MIDIBUFFERSIZE        (1<<13) /* must be power of 2 */
#define MAXPOLYPHONY          64
#define MAXGENERATORS         128
#define OCTAVES               12
#define MAXPORT               32


typedef unsigned short SAMPLEINDEX;


typedef struct SCHEDULEDEVENT {
  int ticker;
  int event0, event1;
} SCHEDULEDEVENT;


typedef struct AHDSR {
  // attack/hold/decay/sustain/release-times are in 1/1024th of a second
  unsigned int attacktime;
  unsigned int holdtime;
  unsigned int decaytime;
  unsigned int decayamount;    // 256=0dB, +-32=+-6dB
  unsigned int sustaintime;    // time it takes to drop by 6dB
} AHDSR;


typedef struct VOICEGENERATOR {
  struct {
    unsigned int monophonic : 1;
  } flags;
  void (* eventhandler)(int, void *, int, int *, int, int, int, int, void *, int);
  int r12;
  int frequency;
} VOICEGENERATOR;


typedef struct SAMPLEDATA {
  union {
    signed short *data;
    VOICEGENERATOR *voice;
  } sampledata;
  unsigned int length, looppoint;
  char name[16];
  struct {
    unsigned int external   : 1; // set -> data in sampledata.data mustn't be free()'d
    unsigned int part       : 1;
    unsigned int monophonic : 1;
  } flags;
  unsigned short usage;          // no. of patches using the sample
  unsigned short noteusage;      // no. of notes using the sample
  unsigned char format;
  SAMPLEINDEX basesample;
} SAMPLEDATA;


typedef struct PATCH {
  SAMPLEINDEX samples[OCTAVES];
  unsigned int frequency[OCTAVES];      // samples/sec to play to get middle-C (note#60)
  AHDSR envelope;
  unsigned int maxduration;             // same units are envelope or 0 for infinite
  char name[16];
} PATCH;


typedef struct DRUM {
  SAMPLEINDEX sample;
  unsigned int frequency;
  AHDSR envelope;
  unsigned int maxduration;             // same units are envelope or 0 for infinite
  char name[16];
} DRUM;


typedef struct CHANNEL {
  unsigned int volume_left, volume_right; // derived from volume and pan
  unsigned char drumchannel, program;
  unsigned char reserved0, reserved1;
  unsigned char controllers[128];
} CHANNEL;


typedef struct NOTE {
  union {
    signed short *data;
    VOICEGENERATOR *voice;
  } sampledata;
  unsigned int length;
  unsigned int resamplerate;
  unsigned int sampleposition;

  unsigned int volume;
  unsigned int maxframes;
  signed int volumestep;

  unsigned char note;                   // midi note
  unsigned char channel;                // channel index
  unsigned char state;                  // attack/hold/decay/sustain/release/done
  unsigned char flags;                  // SILENCE, FORCE_RELEASE
  unsigned char frameposition;          // sample within frame
  unsigned char noteindex;              // index in notes[]
  unsigned char source_format;          // 0 for 16bit, 1 for 8 bit, 2 for voice generator
  unsigned char unused1;

  unsigned int hold_maxframes;
  unsigned int decay_maxframes;
  signed int decay_volumestep;
  unsigned int sustain_maxframes;
  signed int sustain_volumestep;
  unsigned int release_maxframes;
  signed int release_volumestep;

  unsigned int base_resamplerate;       // used to modify resamplerate in realtime
  CHANNEL *channelp;                    // for reading channel volume/pan setting
  unsigned int looppoint;

  SAMPLEDATA *sampleptr;                // sampledata structure

  int private_word;                     // used by voice-generators
} NOTE;


typedef struct MIDIPORT {
  int polyphony;
  unsigned char *activenotesp;
  NOTE *notesp;
  const signed short *sine;             // for vibrato etc.
  const unsigned short *log2lin_volume;
  unsigned int mastervolume;
  unsigned int *workspacep;             // used by the sample-generating routine
  struct {                              // temporary flags used by sample-generator
    unsigned int reserved               : 2;
    unsigned int mono                   : 1;
    unsigned int clearbuffer            : 1;
    unsigned int reduce2_16bit          : 1;
    unsigned int interpolate            : 1;
  } tempflags;
  struct {
    unsigned int reserved               : 5;
    unsigned int interpolate            : 1;
  } defaults;
  // MIDI time code
  unsigned char mtc_h;
  unsigned char mtc_m;
  unsigned char mtc_s;
  unsigned char mtc_f;
  unsigned char mtc_qf;
  unsigned char mtc_format;
  unsigned char reserved0, reserved1;

  // MIDI data buffer
  int running_status;
  unsigned char midibytes[MIDIBUFFERSIZE+16];
  int midibytecount;
  int midireadpos;
  int midiwritepos;
  int wait_for_sysex_end;

  CHANNEL channels[16];

  unsigned char activenotes[MAXPOLYPHONY>>3]; // 1 bit for each possible note
  NOTE notes[MAXPOLYPHONY];

  int enabledchannels;
  int framespersecond;
  int frequency;
  int basechannel;
  int tuning;                            // semi-notes to add to each note
  struct {
    unsigned int omni       : 1;
    unsigned int polyphonic : 1;        // monophonic not supported
  } flags;

  unsigned int workspace[256*2];        //
} MIDIPORT;
